/* Copyright (C) 2011-2012 SBA Research gGmbh

   This file is part of the Slibc Library.

   The Slibc Library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
   License as published by the Free Software Foundation; either
   version 2.1 of the License, or (at your option) any later version.

   The Slibc library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public
   License along with the Slibc Library; if not, see
   <http://www.gnu.org/licenses/>.  
*/
///////////////////////////////////////////////////////
/// @file
/// Contains those _s-functions that are related to stdio
///////////////////////////////////////////////////////
#include_next <stdio.h>

#ifndef SLIBC_STDIO_H
#define SLIBC_STDIO_H

// TR 24731-1 is not available if __STDC_WANT_LIB_EXT1__ equals 0
#if (!defined(__STDC_WANT_LIB_EXT1__) || (__STDC_WANT_LIB_EXT1__ != 0))

// normally stdlib.h includes stdarg.h but it depends
// on compilaton flags. since we use the standard va_list
// we include it.
#include <stdarg.h>
#include "./base_.h"
#include "./stddef.h"
#include "./errno.h"

SLIBC_BEGIN_DECLS

/// Specifies the array size required for storing temporary filenames generated by tmpnam_s
#if ((L_tmpnam) > 25)
# define L_tmpnam_s L_tmpnam
#else
# define L_tmpnam_s 25
#endif

/// maximum amount of unique filenames, which function tmpnam_s can generate
#define TMP_MAX_S TMP_MAX
	

///////////////////////////////////////////////////////////////////////////////
///   This function creates a temporary file.
///
///   The temporary file is guaranteed to be different from any other existing 
///   file. The file is opend in binary read/write (w+b) mode. When the file is
///   closed or the program teminates the file is removed automatically. 
///
///   @remark In contrast to tmpfile, tmpfile_s returns a file with exclusive access
///   and 600 permissions.
///
///   By default, the file is created in /tmp. However, it is possible
///   to change this directory by calling slibc_set_tmp_dir.
///
///   @rcs A runtime-constraint violation occurs if
///    \li streamptr is a NULL pointer
///
///   @param [out] streamptr  pointer to the temporary file created
///
///   @return 0 if the file was created successfully.
///           A non-zero value is returned if the file could not be created or 
///           there was a runtime-constraint violation.
///
///   @see    tmpfile
///////////////////////////////////////////////////////////////////////////////

errno_t tmpfile_s(FILE * restrict * restrict streamptr);


///////////////////////////////////////////////////////////////////////////////
///   This function creates a file or directory name that is unique for the 
///   specified temporary directory.
///
///   The generated file or directory name is guaranteed to be different from
///   any other existing name in the temporary directory. The default
///   temporary directory is /tmp but can be changed via slibc_set_tmp_dir.
///   The output buffer needs to be at least of length L_tmpnam_s if the
///   default directory location of /tmp is used. In case the slibc temporary directory
///   is changed to a longer directory name by calling slibc_set_tmp_dir the
///   output buffer is required to be of size L_tmpnam_s + strlen(set_tmp_dir). Otherwise
///   calling tmpnam_s might fail. (It will never overflow the buffer though).
///   The function is potentially capable of generating TMP_MAX_S different strings.
///
///   @remark Use of this function is normally discouraged because this
///    function does not create the file. It shares this isse wit the traditional
///    tmpnam function. In more detail, a race condition between
///    calling this function and the time of the actual file/directory creation exists.
///    It is, thus, possible that an attacker creates a file with same name in the
///    meantime. Thus, the ISO standard recommends using tmpfile_s where possible.
///    One possible reasonable use of this function is when the user wants to
///    create a temporary directory name. The use of this function is secure in the
///    author's opinion when you have set the temporary directory to a non-shared 
///    directory where only your user is allowed to write. 
///   
///   @param s       [out]  On success s will contain the generated unique temporary file name.
///   @param maxsize [in]   The size of s.
///
///   @return Zero on success.
///           A non-zero value is returned in case of a runtime-constraint 
///           violation or if no suitable string can be generated.
///
///   @see    tmpnam
///////////////////////////////////////////////////////////////////////////////

errno_t tmpnam_s(char *s, rsize_t maxsize);



///////////////////////////////
///   The gets_s function reads one line from stdin into @a s.
///
///   Unlike the traditional gets function a second parameter @a n that specifies
///   the size of @a s is expected. It is considered a runtime-constraint violation
///   if no newline, EOF or read error occurrs within reading @a n-1 bytes.
///   
///   @param [out] s   the target buffer 
///   @param [in]  n   the size of @a s
///
///   @return The gets_s function returns s if successful. 
///           NULL is returned if there was a runtime-constraint violation or
///           if end-of-file is encountered and no caracters have been read into the array 
///           or if a read error occured.
///
///   @see    gets
///////////////////////////////

char *gets_s(char *s, rsize_t n);


///////////////////////////////
///   The fopen_s function opens the file specified by @a filename.
///
///   @rcs A runtime-constraint violation occurs 
///    @li streamptr is a null pointer
///    @li filename is a null pointer
///    @li MODE is a null pointer
///
///   @param [out] streamptr On success it is set to the opened FILE * stream.
///   @param [in]  filename  the name of the file to be opened
///   @param [in]  mode      determines how the file should be opend. It 
///                          supports the same flags as fopen with some additions.
///
///   @return Zero if the file was successfully opened.
///           Non-zero if it could not open the file or a runtime-constraint 
///           violation occurred.
///
///   @see    fopen
///////////////////////////////

errno_t fopen_s(FILE * restrict * restrict streamptr,
				 const char * restrict filename,
				 const char * restrict mode);


///////////////////////////////
///   The freopen_s function opens @a filename and closes @a stream.
///
///   @rcs A runtime-constraint violation occurs 
///    @li newstreamptr is a null pointer
///    @li stream is a null pointer
///    @li mode is a null pointer
///
///   @param [out] newstreamptr contains the result of opening @a filename
///   @param [in]  filename     the name of the file to be opened  
///   @param [in]  mode         determines how the file should be opened. same meaning as for fopen_s
///   @param [in]  stream       the stream to be closed
///
///   @return Zero if the file was successfully opened.
///           Non-zero if it could not open the file or a runtime-constraint 
///           violation occurred.
///
///   @see    freopen
///////////////////////////////

errno_t freopen_s(FILE * restrict * restrict newstreamptr,
		  const char * restrict filename,
		  const char * restrict mode,
		  FILE * restrict stream);



///////////////////////////////////////////////////////
/// This function allows fomatted output into buffer @a s while taking into account its size.
/// 
/// A maximum of n-1 characters are written into the buffer s, followed by a zero byte.
/// 
/// The sprintf_s function is equivalent to the sprintf function except the
/// following. The %n specifier (modified or not by flags, field width, or 
/// precision) shall not appear in the string pointed to by format.
/// 
/// The sprintf_s function, unlike snprintf_s, treats a result too big 
/// for the array pointed to by s as a runtime-constraint violation.
///
/// @param [out] s       destination buffer containing the output
/// @param [in]  n       size of buffer s
/// @param [in]  format  format string (equal to printf)
/// @param [in]  ...     a variable number of arguments corresponding to the given format string
///
/// @return 
///   the number of characters written (not counting the null byte) 
///   a negative number in case of an encoding error
///   0 in case of runtime-constraint violation
///////////////////////////////////////////////////////

int sprintf_s(char * restrict s, 
			  rsize_t n,
			  const char * restrict format, ...) 
	__attribute__ ((format (printf, 3, 4)));


///////////////////////////////////////////////////////
/// This function allows fomatted output into buffer @a s while taking into account its size.
/// 
/// A maximum of n-1 characters are written into the buffer s, followed by a zero byte.
///
/// The snprintf_s function is equivalent to the sprintf function except the
/// following. The %n specifier (modified or not by flags, field width, or 
/// precision) shall not appear in the string pointed to by format.
/// 
/// The snprintf_s function, unlike sprintf_s, will truncate the result to 
/// fit within the array pointed to by s.
///
/// The output is made only without truncation, if the return value 
/// is positive (> 0) and the returned value <n.
///
/// @param [out] s       destination buffer containing the output
/// @param [in]  n       size of buffer s
/// @param [in]  format  format-string (equal to printf)
/// @param [in]  ...     a variable number of arguments corresponding to the given format flags
///
/// @return 
///   the number of characters that would have been written (not counting the 
///     null byte) had the buffer been sufficiently large
///   a negative number in case of a runtime-constraint violation
///   Thus, the output has been completely written if and only if a positive
///   value that is less than n is returned.
///////////////////////////////////////////////////////

int snprintf_s(char * restrict s, 
			   rsize_t n,
			   const char * restrict format, ...) 
	__attribute__ ((format (printf, 3, 4)));


///////////////////////////////////////////////////////
/// The vsprintf_s function is equivalent to sprintf_s but expects a va_list argument.
/// 
/// @param [out] s       destination buffer containing the output
/// @param [in]  n       size of buffer s
/// @param [in]  format  format-string (equal to printf)
/// @param [in]  arg     list of variable arguments.
///
/// @return 
///   the number of characters written (not counting the null byte) 
///   a negative number in case of an encoding error
///   0 in case of runtime-constraint violation
///
/// @see
///   sprintf_s
///////////////////////////////////////////////////////

int vsprintf_s(char * restrict s, 
			   rsize_t n,
			   const char * restrict format,
			   va_list arg) 
	__attribute__ ((format (printf, 3, 0)));


///////////////////////////////////////////////////////
/// The vsnprintf_s function is equivalent to snprintf_s but expects a va_list argument.
///
/// @param [out] s       destination buffer containing the output
/// @param [in]  n       size of buffer s
/// @param [in]  format  format-string (equal to printf)
/// @param [in]  arg     a variable number of arguments corresponding to the given format flags
///
/// @return 
///   the number of characters that would have been written (not counting the 
///     null byte) had the buffer been sufficiently large
///   a negative number in case of a runtime-constraint violation
///   Thus, the output has been completely written if and only if a positive
///   value that is less than n is returned.
///
/// @see
///   snprintf_s
///////////////////////////////////////////////////////

int vsnprintf_s(char * restrict s, 
				rsize_t n,
				const char * restrict format,
				va_list arg)
	__attribute__ ((format (printf, 3, 0)));
	

///////////////////////////////
///   The fprintf_s function is analogous to the @a fprintf function except 
///   that the @a %n specifier is not allowed.
///
///   @param [in] stream   the output stream
///   @param [in] format   printf-style format flags (%n disallowed)
///   @param [in] ...      a variable number of arguments corresponding to the given format flags
///
///   @return 
///     the number of characters written
///     a negative value in case of an output error or runtime constraint violation
///
///   @see    fprintf
///////////////////////////////

int fprintf_s(FILE * restrict stream,
	       const char * restrict format, ...);


///////////////////////////////
///   The vfprintf_s function is equivalent to fprintf_s but expects a va_list argument.
///
///   @param [in] stream the output stream
///   @param [in] format printf-style format flags (@a %n disallowed)
///   @param [in] arg    va_list initialized by @a va_start
///
///   @return 
///     the number of characters written
///     a negative value in case of an output error or runtime constraint violation
///
///   @see    fprintf_s
///////////////////////////////

int vfprintf_s(FILE * restrict stream,
	       const char * restrict format, va_list arg);
	
	
///////////////////////////////
///   The printf_s function behaves as fprintf_s when fprintf_s is called with an argument of stdout.
///
///   @param [in] format  printf-style format flags (%n disallowed)
///   @param [in] ...     a variable number of arguments corresponding to the given format flags
///
///   @return 
///     the number of characters written
///     a negative value in case of an output error or runtime constraint violation
///
///   @see    fprintf_s
///////////////////////////////

int printf_s(const char * restrict format, ...);
	


///////////////////////////////
///   The vprintf_s function is equivalent to printf_s but expects a va_list argument.	
///
///   @param [in] format printf-style format string
///   @param [in] arg    
///
///   @return 
///     the number of characters written
///     a negative value in case of an output error or runtime constraint violation
///
///   @see    printf_s
///////////////////////////////

int vprintf_s(const char * restrict format,
	      va_list arg);

		  
///////////////////////////////
///   The scanf_s function behaves as fscanf_s when fscanf_s is called with an argument of stdin.
///
///   @param [in]  format  scanf-style format string
///   @param [out] ...    a variable number of arguments corresponding to the given format string
///
///   @return EOF if there was a runtime-constraint violation or an input 
///             failure occurred before any conversion.
///           Otherwise the number of successfully assigned input items is returned.
///
///   @see    fscanf_s
///////////////////////////////

int scanf_s(const char * restrict format, ...);


///////////////////////////////
///   The vscanf_s function is equivalent to scanf_s but expects a va_list argument.
///
///   @param [in]  format
///   @param [out] arg
///
///   @return EOF if there was a runtime-constraint violation or an input 
///             failure occurred before any conversion.
///           Otherwise the number of successfully assigned input items is returned.
///
///   @see    scanf_s
///////////////////////////////

int vscanf_s(const char * restrict format, va_list arg);


///////////////////////////////
///   The vsscanf_s function is equivalent to sscanf_s but expects a va_list argument.
///
///   @param [in]  s       the string to be parsed
///   @param [in]  format  scanf-style format string
///   @param [out] arg     va_list argument
///
///   @return EOF if there was a runtime-constraint violation or an input 
///             failure occurred before any conversion.
///           Otherwise the number of successfully assigned input items is returned.
///
///   @see    sscanf_s
///////////////////////////////

int vsscanf_s(const char * restrict s,
			  const char * restrict format, va_list arg);


///////////////////////////////////////////////////////////////////////////////		  
///   The sscanf_s function  is analogous to fscanf_s but reads from a string instead of a stream.
///
///   @param [in] s      the string to be parsed
///   @param [in] format scanf-style format string
///   @param [out] ...   a variable number of arguments corresponding to the given format string
///
///   @return EOF if there was a runtime-constraint violation or an input 
///             failure occurred before any conversion.
///           Otherwise the number of successfully assigned input items is returned.
///   @see    fscanf_s
///////////////////////////////////////////////////////////////////////////////		  
int sscanf_s(const char * restrict s,
	      const char * restrict format, ...);
		  

///////////////////////////////////////////////////////////////////////////////
///   A secure variant of fscanf that expects the caller to specify the size for each buffer argument.
///
///   The fscanf_s function is equivalent to fscanf but handles the c, s, and 
///   [ conversion specifiers differently. These conversion specifiers now expect
///   a pair of arguments: the first one is a pointer to a buffer (as before) while
///   the second one is expected to be of type rsize_t and specifies the size of the 
///   buffer.
///
///   @param [in]  stream
///   @param [in]  format
///   @param [out] ...  a variable number of arguments corresponding to the given format string
///
///   @return EOF if there was a runtime-constraint violation or an input 
///             failure occurred before any conversion.
///           Otherwise the number of successfully assigned input items is returned.
///
///   @see    fscanf
///////////////////////////////////////////////////////////////////////////////

int fscanf_s(FILE * restrict stream,
	     	const char * restrict format, ...);
			
			
///////////////////////////////////////////////////////////////////////////////
///   vfscanf_s is equivalent to fscanf_s but expects a va_list argument.
///
///   @param [in]  stream  the input stream
///   @param [in]  format  the format string
///   @param [out] arg     contains the variable argument list initialized by the va_start macro
///
///   @return EOF if there was a runtime-constraint violation or an input 
///             failure occurred before any conversion.
///           Otherwise the number of successfully assigned input items is returned.
///
///   @see    fscanf_s
///////////////////////////////////////////////////////////////////////////////

int vfscanf_s(FILE * restrict stream,
	     	const char * restrict format, va_list arg);

SLIBC_END_DECLS

#if defined(__cplusplus) && (defined(SLIBC_WANT_TEMPLATES))
# include "./stdio_templates_.hpp"
#endif

#if (defined(SLIBC_WANT_MKTEMP))
# include "./stdio_ext_.h"
#endif

#endif //(!defined(__STDC_WANT_LIB_EXT1__) || (__STDC_WANT_LIB_EXT1__ != 0))

#endif
